#ifndef PROTOCOL_HPP
#define PROTOCOL_HPP

#include <iostream>
#include "log.hpp"
#include <string>
#include <jsoncpp/json/json.h>

// #define Myself 1

const std::string spacesep = " ";
const std::string separator = "\n";

// 编码函数，将文本编码成特定格式的字符串
std::string Encode(std::string &text)
{
    std::string package = std::to_string(text.size());
    package += separator;
    package += text;
    package += separator;
    return package;
}

// 解码函数，从编码后的字符串提取出原始文本
bool Decode(std::string &package, std::string *text)
{
    // "len"\n"num1 op num2"\n 或 "len"\n"result code"\n

    size_t pos = package.find(separator);
    if (pos == std::string::npos)
        return false;

    std::string len_str = package.substr(0, pos);
    size_t len = std::stoi(len_str);

    size_t total_len = len_str.size() + len + 2;
    if (package.size() < total_len)
    {
        return false;
    }

    *text = package.substr(pos + 1, len);
    // 移除已提取的报文内容
    package.erase(0, total_len);

    return true;
}

class Request
{
public:
    Request(int num1, int num2, char op) : num1_(num1), num2_(num2), op_(op) {}
    Request() {}

public:
    int GetNum1() const { return num1_; }
    int GetNum2() const { return num2_; }
    char GetOp() const { return op_; }

    void DebugPrint()
    {
        std::cout << std::endl
                  << "New Request: " << num1_ << op_ << num2_ << " =? " << std::endl;
    }

public:
    // 序列化请求对象，转为字符串
    bool Serialize(std::string *out)
    {
#ifdef Myself
        std::string s = std::to_string(num1_);
        s += spacesep; // 数据之间的分隔符
        s += op_;
        s += spacesep;
        s += std::to_string(num2_);

        *out = s;

        return true;
#else
        // JSON 格式序列化

        Json::Value root;
        root["x"] = num1_;
        root["y"] = num2_;
        root["op"] = op_;

        Json::StyledWriter w;
        *out = w.write(root);
        return true;
#endif
    }

    // 反序列化字符串，转为请求对象
    bool Deserialize(const std::string &str)
    {
#ifdef Myself
        size_t left = str.find(spacesep);
        if (left == std::string::npos)
            return false;

        std::string num1 = str.substr(0, left);
        size_t right = str.rfind(spacesep);

        if (right == std::string::npos)
            return false;

        std::string num2 = str.substr(right + 1);

        if (left + 2 != right)
            return false;

        op_ = str[left + 1];
        num1_ = std::stoi(num1);
        num2_ = std::stoi(num2);

        return true;
#else
        // JSON 格式反序列化
        Json::Value root;
        Json::Reader r;
        r.parse(str, root);

        num1_ = root["x"].asInt();
        num2_ = root["y"].asInt();
        op_ = root["op"].asInt();

        return true;
#endif
    }

private:
    int num1_; // 操作数1
    int num2_; // 操作数2
    char op_;  // 运算符
};

class Response
{
public:
    Response(int res, int code) : result_(res), code_(code) {}
    Response() {}

public:
    int GetResult() const { return result_; }
    int GetCode() const { return code_; }

public:
    // 序列化响应对象，转为字符串
    bool Serialize(std::string *out)
    {
#ifdef Myself
        std::string s = std::to_string(result_);
        s += spacesep;
        s += std::to_string(code_);

        *out = s;
        return true;
#else
        // JSON 格式序列化

        Json::Value root;
        root["result"] = result_;
        root["code"] = code_;

        Json::StyledWriter w;
        *out = w.write(root);
        return true;
#endif
    }

    // 反序列化字符串，转为响应对象
    bool Deserialize(const std::string &str)
    {
#ifdef Myself
        size_t pos = str.find(spacesep);

        if (pos == std::string::npos)
        {
            return false;
        }

        std::string resultstr = str.substr(0, pos);
        std::string codestr = str.substr(pos + 1);

        result_ = std::stoi(resultstr);
        code_ = std::stoi(codestr);

        return true;
#else
        // JSON 格式反序列化

        Json::Value root;
        Json::Reader r;
        r.parse(str, root);

        result_ = root["result"].asInt();
        code_ = root["code"].asInt();
        return true;
#endif
    }

    void DebugPrint()
    {
        std::cout << std::endl
                  << "New Response: result = " << result_ << ", code = " << code_ << std::endl;
        std::cout << "####################################" << std::endl;
    }

private:
    int result_; // 运算结果
    int code_;   // 错误码
};

#endif // PROTOCOL_HPP
